package com.lagouedu.cfgcenter.task;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.lagouedu.cfgcenter.Constants;
import com.lagouedu.cfgcenter.config.DatabaseConfig;
import com.lagouedu.cfgcenter.controller.TestController;
import org.I0Itec.zkclient.IZkDataListener;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.sql.DataSource;
import java.lang.reflect.Method;

/*
* 启动zookeeper 节点数据变化监听
* */
@Component
public class ConfigListennerTask implements ApplicationRunner {

    @Qualifier("dataResourceConfig")
    @Autowired
    private DatabaseConfig databaseConfig;

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    DefaultListableBeanFactory beanFactory;

    {
        if(!Constants.zkClient.exists("/config/datasource")){
            Constants.zkClient.createPersistent("/config/datasource", true);
        }

        if(!Constants.zkClient.exists(Constants.datasourceUrl)){
            Constants.zkClient.createPersistent(Constants.datasourceUrl, "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true&serverTimezone=UTC");
        }
        if(!Constants.zkClient.exists(Constants.datasourceUserName)){
            Constants.zkClient.createPersistent(Constants.datasourceUserName, "root");
        }
        if(!Constants.zkClient.exists(Constants.datasourcePassword)){
            Constants.zkClient.createPersistent(Constants.datasourcePassword, "root");
        }
        if(!Constants.zkClient.exists(Constants.driverClass)){
            Constants.zkClient.createPersistent(Constants.driverClass, "com.mysql.cj.jdbc.Driver");
        }
    }
    @Override
    public void run(ApplicationArguments args) throws Exception {

        // 监控 url 是否变更
        Constants.zkClient.subscribeDataChanges(Constants.datasourceUrl, new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {
                // 数据变动则销毁 druid连接池重新创建
                databaseConfig.setDatasourceUrl(o.toString());
                DatabaseConfig bean = (DatabaseConfig) applicationContext.getBean("dataResourceConfig");
                //通过反射修改属性值
                Method declaredMethod = DatabaseConfig.class.getDeclaredMethod("setDatasourceUrl", String.class);
                declaredMethod.invoke(bean,o.toString());

                // 销毁之前的连接池
                DruidDataSource bean1 = (DruidDataSource) applicationContext.getBean("druidDataSrouce");
                DruidDataSource.DestroyConnectionThread.interrupted();
                bean1.close();
                // 创建新的连接池并注册到spring中
                DruidDataSource dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(databaseConfig.toMap());
                TestController bean2 = applicationContext.getBean(TestController.class);
                bean2.setDruidDataSource(dataSource);

            }

            @Override
            public void handleDataDeleted(String s) throws Exception {

            }
        });

        // 监控 用户名是否变更
        Constants.zkClient.subscribeDataChanges(Constants.datasourceUserName, new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

                DatabaseConfig bean = (DatabaseConfig) applicationContext.getBean("dataResourceConfig");
                //通过反射修改属性值
                Method declaredMethod = DatabaseConfig.class.getDeclaredMethod("setDatasourceUserName", String.class);
                declaredMethod.invoke(bean,o.toString());

                // 销毁之前的连接池
                DruidDataSource bean1 = (DruidDataSource) applicationContext.getBean("druidDataSrouce");
                DruidDataSource.DestroyConnectionThread.interrupted();
                bean1.close();
                // 创建新的连接池并注册到spring中
                DruidDataSource dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(databaseConfig.toMap());
                TestController bean2 = applicationContext.getBean(TestController.class);
                bean2.setDruidDataSource(dataSource);

            }

            @Override
            public void handleDataDeleted(String s) throws Exception {

            }
        });

        // 监控 密码是否变更
        Constants.zkClient.subscribeDataChanges(Constants.datasourcePassword, new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

                DatabaseConfig bean = (DatabaseConfig) applicationContext.getBean("dataResourceConfig");
                //通过反射修改属性值
                Method declaredMethod = DatabaseConfig.class.getDeclaredMethod("setDatasourcePassword", String.class);
                declaredMethod.invoke(bean,o.toString());

                // 销毁之前的连接池
                DruidDataSource bean1 = (DruidDataSource) applicationContext.getBean("druidDataSrouce");
                DruidDataSource.DestroyConnectionThread.interrupted();
                bean1.close();
                // 创建新的连接池并注册到spring中
                DruidDataSource dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(databaseConfig.toMap());
                TestController bean2 = applicationContext.getBean(TestController.class);
                bean2.setDruidDataSource(dataSource);

            }

            @Override
            public void handleDataDeleted(String s) throws Exception {

            }
        });
    }

}
